package com.jvyou.app.ds.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jvyou.app.common.constants.BaseConstants;
import com.jvyou.app.common.domain.model.PageResult;
import com.jvyou.app.common.enums.HttpCodeEnum;
import com.jvyou.app.common.exception.AppException;
import com.jvyou.app.common.utils.orm.WrapperTool;
import com.jvyou.app.ds.domain.dto.QuestionDto;
import com.jvyou.app.ds.domain.entity.*;
import com.jvyou.app.ds.domain.vo.NextQuestionVo;
import com.jvyou.app.ds.mapper.*;
import com.jvyou.app.ds.service.QuestionOptionService;
import com.jvyou.app.ds.service.QuestionService;
import com.jvyou.app.ds.service.SparkMessageService;
import com.jvyou.app.ds.utils.QuestionParser;
import com.jvyou.app.ds.utils.login.LoginContext;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;


/**
 * 驾校题目表(Question)表服务实现类
 *
 * @author 橘柚
 * @since 2025-04-20 20:55:04
 */
@Service("questionService")
@RequiredArgsConstructor
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService {

    private final LicenseTypeMapper licenseTypeMapper;
    private final CourseSubjectMapper courseSubjectMapper;
    private final QuestionTypeMapper questionTypeMapper;
    private final StudentMapper studentMapper;
    private final AnswerSessionMapper answerSessionMapper;
    private final AnswerRecordMapper answerRecordMapper;
    private final QuestionMapper questionMapper;
    private final QuestionOptionMapper questionOptionMapper;
    private final QuestionOptionService questionOptionService;
    private final SparkMessageService sparkMessageService;

    private QueryWrapper<Question> getWrapper(QuestionDto questionDto) {
        QueryWrapper<Question> queryWrapper = new QueryWrapper<>();
        WrapperTool.notEmptyEq(queryWrapper, "type_id", questionDto.getTypeId());
        WrapperTool.notEmptyEq(queryWrapper, "license_type_id", questionDto.getLicenseTypeId());
        WrapperTool.notEmptyEq(queryWrapper, "course_type_id", questionDto.getCourseTypeId());
        WrapperTool.notEmptyEq(queryWrapper, "question_type", questionDto.getQuestionType());
        WrapperTool.notEmptyEq(queryWrapper, "is_new_rule", questionDto.getIsNewRule());
        WrapperTool.notEmptyEq(queryWrapper, "is_hot", questionDto.getIsHot());
        WrapperTool.notEmptyEq(queryWrapper, "difficulty", questionDto.getDifficulty());
        WrapperTool.notEmptyEq(queryWrapper, "status", questionDto.getStatus());
        WrapperTool.notEmptyEq(queryWrapper, "source", questionDto.getSource());
        WrapperTool.notEmptyLike(queryWrapper, "content", questionDto.getContent());
        return queryWrapper;
    }

    @Override
    public List<Question> listQuestion(QuestionDto questionDto) {
        return list(getWrapper(questionDto));
    }


    @Override
    public PageResult<Question> pageQuestion(QuestionDto questionDto) {
        IPage<Question> page = new Page<>(questionDto.getCurrent(), questionDto.getPageSize());
        page = page(page, getWrapper(questionDto));
        for (Question question : page.getRecords()) {
            LicenseType licenseType = licenseTypeMapper.selectById(question.getLicenseTypeId());
            if (licenseType != null) {
                question.setLicenseTypeCode(licenseType.getLicenseCode());
                question.setLicenseTypeName(licenseType.getLicenseName());
                question.setLicenseTypColor(licenseType.getColor());
            }
            CourseSubject courseSubject = courseSubjectMapper.selectById(question.getCourseTypeId());
            if (courseSubject != null) {
                question.setCourseSubjectName(courseSubject.getSubjectName());
                question.setCourseSubjectColor(courseSubject.getColor());
            }
            QuestionType questionType = questionTypeMapper.selectById(question.getTypeId());
            if (questionType != null) {
                question.setQuestionTypeName(questionType.getName());
            }
        }
        return PageResult.success(page);
    }

    @Override
    public NextQuestionVo getNextQuestion(QuestionDto questionDto) {
        // 1. 查询学生信息
        Long userId = LoginContext.getUserId();
        Student student = studentMapper.getByUser(userId);
        if (student == null) {
            throw new AppException(HttpCodeEnum.DATA_NOT_EXIST, "学员信息异常，查询不到学员信息");
        }
        // 2. 查询会话信息
        LambdaQueryWrapper<AnswerSession> answerSessionEw = new LambdaQueryWrapper<>();
        answerSessionEw.eq(AnswerSession::getStudentId, student.getId());
        answerSessionEw.eq(AnswerSession::getLicenseType, questionDto.getLicenseType());
        answerSessionEw.eq(AnswerSession::getSubject, questionDto.getSubject());
        answerSessionEw.eq(AnswerSession::getIsCurrent, BaseConstants.YES);
        answerSessionEw.last("limit 1");
        AnswerSession answerSession = answerSessionMapper.selectOne(answerSessionEw);
        // 3. 会话为空则创建会话
        if (answerSession == null) {
            answerSession = new AnswerSession();
            answerSession.setStudentId(student.getId());
            answerSession.setLicenseType(questionDto.getLicenseType());
            answerSession.setSubject(questionDto.getSubject());
            answerSession.setIsCurrent(BaseConstants.YES);
            answerSessionMapper.insert(answerSession);
        }
        // 4. 判断当前会话已经作答多少
        Long sessionId = answerSession.getId();
        Integer current = answerSessionMapper.getCurrentNum(sessionId);
        NextQuestionVo nextQuestionVo = new NextQuestionVo();
        nextQuestionVo.setCurrent(current + 1);
        // 5. 查询所有题目数量
        LicenseType licenseType = licenseTypeMapper.getByLicenseCode(questionDto.getLicenseType());
        if (licenseType == null) {
            throw new AppException(HttpCodeEnum.DATA_NOT_EXIST, "查询不到该驾照类型");
        }
        CourseSubject courseSubject = courseSubjectMapper.getBySubject(questionDto.getSubject());
        if (courseSubject == null) {
            throw new AppException(HttpCodeEnum.DATA_NOT_EXIST, "查询不到该科目");
        }
        LambdaQueryWrapper<Question> questionEw = new LambdaQueryWrapper<>();
        questionEw.eq(Question::getLicenseTypeId, licenseType.getId());
        questionEw.eq(Question::getCourseTypeId, courseSubject.getId());
        questionEw.eq(Question::getStatus, BaseConstants.YES);
        questionEw.eq(Question::getSource, "local");
        int total = questionMapper.selectCount(questionEw).intValue();
        if (total == 0) {
            throw new AppException(HttpCodeEnum.DATA_NOT_EXIST, "该科目下没有题目");
        }
        nextQuestionVo.setTotal(total);
        // 6. 查询当前会话未答题的下一道题目数量
        questionEw = new LambdaQueryWrapper<>();
        questionEw.eq(Question::getLicenseTypeId, licenseType.getId());
        questionEw.eq(Question::getCourseTypeId, courseSubject.getId());
        questionEw.eq(Question::getStatus, BaseConstants.YES);
        questionEw.notInSql(Question::getId, "select question_id from ds_answer_record where session_id = " + answerSession.getId());
        questionEw.last("limit 1");
        Question question = questionMapper.selectOne(questionEw);
        if (question == null) {
            throw new AppException(HttpCodeEnum.DATA_NOT_EXIST, "该科目下没有题目");
        }
        nextQuestionVo.setId(question.getId());
        nextQuestionVo.setContent(question.getContent());
        nextQuestionVo.setContentImage(question.getContentImage());
        nextQuestionVo.setExplanation(question.getExplanation());
        nextQuestionVo.setKeyPoint(question.getKeyPoint());
        nextQuestionVo.setIsNewRule(question.getIsNewRule());
        nextQuestionVo.setIsHot(question.getIsHot());
        nextQuestionVo.setDifficulty(question.getDifficulty());
        nextQuestionVo.setStatus(question.getStatus());
        nextQuestionVo.setSource(question.getSource());
        nextQuestionVo.setQuestionType(question.getQuestionType());
        // 查询题目选项
        LambdaQueryWrapper<QuestionOption> questionOptionEw = new LambdaQueryWrapper<>();
        questionOptionEw.eq(QuestionOption::getQuestionId, question.getId());
        questionOptionEw.orderByAsc(QuestionOption::getSortOrder);
        List<QuestionOption> questionOptions = questionOptionMapper.selectList(questionOptionEw);
        nextQuestionVo.setOptions(questionOptions);
        List<String> answers = questionOptions.stream()
                .filter(questionOption -> questionOption.getIsCorrect().equals(BaseConstants.YES))
                .map(QuestionOption::getOptionCode)
                .collect(Collectors.toList());
        nextQuestionVo.setAnswers(answers);
        // 查询正确率
        Double correctRate = answerRecordMapper.getCorrectRate(question.getId());
        nextQuestionVo.setCorrectRate(correctRate == null ? 0 : correctRate);
        nextQuestionVo.setSessionId(sessionId);
        nextQuestionVo.setIsLast(current >= total ? BaseConstants.YES : BaseConstants.NO);
        return nextQuestionVo;
    }

    @Override
    public NextQuestionVo getCurrentAnswerRecord(QuestionDto questionDto) {
        // 1. 查询学生信息
        Long userId = LoginContext.getUserId();
        Student student = studentMapper.getByUser(userId);
        if (student == null) {
            throw new AppException(HttpCodeEnum.DATA_NOT_EXIST, "学员信息异常，查询不到学员信息");
        }
        // 2. 查询会话信息
        LambdaQueryWrapper<AnswerSession> answerSessionEw = new LambdaQueryWrapper<>();
        answerSessionEw.eq(AnswerSession::getStudentId, student.getId());
        answerSessionEw.eq(AnswerSession::getLicenseType, questionDto.getLicenseType());
        answerSessionEw.eq(AnswerSession::getSubject, questionDto.getSubject());
        answerSessionEw.eq(AnswerSession::getIsCurrent, BaseConstants.YES);
        answerSessionEw.last("limit 1");
        AnswerSession answerSession = answerSessionMapper.selectOne(answerSessionEw);
        // 3. 会话为空则创建会话
        if (answerSession == null) {
            answerSession = new AnswerSession();
            answerSession.setStudentId(student.getId());
            answerSession.setLicenseType(questionDto.getLicenseType());
            answerSession.setSubject(questionDto.getSubject());
            answerSession.setIsCurrent(BaseConstants.YES);
            answerSessionMapper.insert(answerSession);
        }
        // 4. 判断当前会话已经作答多少
        Long sessionId = answerSession.getId();
        Integer current = answerSessionMapper.getCurrentNum(sessionId);
        NextQuestionVo nextQuestionVo = new NextQuestionVo();
        nextQuestionVo.setCurrent(current + 1);
        // 5. 查询所有题目数量
        LicenseType licenseType = licenseTypeMapper.getByLicenseCode(questionDto.getLicenseType());
        if (licenseType == null) {
            throw new AppException(HttpCodeEnum.DATA_NOT_EXIST, "查询不到该驾照类型");
        }
        CourseSubject courseSubject = courseSubjectMapper.getBySubject(questionDto.getSubject());
        if (courseSubject == null) {
            throw new AppException(HttpCodeEnum.DATA_NOT_EXIST, "查询不到该科目");
        }
        LambdaQueryWrapper<Question> questionEw = new LambdaQueryWrapper<>();
        questionEw.eq(Question::getLicenseTypeId, licenseType.getId());
        questionEw.eq(Question::getCourseTypeId, courseSubject.getId());
        questionEw.eq(Question::getStatus, BaseConstants.YES);
        questionEw.eq(Question::getSource, "local");
        int total = questionMapper.selectCount(questionEw).intValue();
        if (total == 0) {
            throw new AppException(HttpCodeEnum.DATA_NOT_EXIST, "该科目下没有题目");
        }
        nextQuestionVo.setTotal(total);
        return nextQuestionVo;
    }

    @Transactional
    @Override
    public NextQuestionVo getNextAiQuestion() {
        String subjectOneChoice = sparkMessageService.subjectOneChoice();
        QuestionParser.QuestionParseResult result = QuestionParser.parseFromAiContent(subjectOneChoice);
        Question question = null;
        List<QuestionOption> options = null;
        if (result == null) {
            LambdaQueryWrapper<Question> questionEw = new LambdaQueryWrapper<>();
            questionEw.eq(Question::getStatus, BaseConstants.YES);
            questionEw.last("limit 1");
            question = questionMapper.selectOne(questionEw);
            options = questionMapper.getOptions(question.getId());
        } else {
            question = result.getQuestion();
            options = result.getOptions();
        }

        NextQuestionVo nextQuestionVo = new NextQuestionVo();
        nextQuestionVo.setId(question.getId());
        nextQuestionVo.setContent(question.getContent());
        nextQuestionVo.setContentImage(question.getContentImage());
        nextQuestionVo.setExplanation(question.getExplanation());
        nextQuestionVo.setKeyPoint(question.getKeyPoint());
        nextQuestionVo.setIsNewRule(question.getIsNewRule());
        nextQuestionVo.setIsHot(question.getIsHot());
        nextQuestionVo.setDifficulty(question.getDifficulty());
        nextQuestionVo.setStatus(question.getStatus());
        nextQuestionVo.setSource(question.getSource());
        nextQuestionVo.setQuestionType(question.getQuestionType());
        nextQuestionVo.setOptions(options);
        nextQuestionVo.setAnswers(options.stream()
                .filter(questionOption -> questionOption.getIsCorrect().equals(BaseConstants.YES))
                .map(QuestionOption::getOptionCode)
                .collect(Collectors.toList()));
        question.setId(IdUtil.getSnowflakeNextId());
        questionMapper.insert(question);
        nextQuestionVo.setId(question.getId());
        for (QuestionOption option : options) {
            option.setQuestionId(question.getId());
        }
        questionOptionService.saveBatch(options);
        return nextQuestionVo;
    }

    @Override
    public NextQuestionVo getNextErrorQuestion() {
        Question question = questionMapper.getNextErrorQuestion();
        if (question == null){
            return null;
        }
        NextQuestionVo nextQuestionVo = new NextQuestionVo();

        nextQuestionVo.setId(question.getId());
        nextQuestionVo.setContent(question.getContent());
        nextQuestionVo.setContentImage(question.getContentImage());
        nextQuestionVo.setKeyPoint(question.getKeyPoint());
        nextQuestionVo.setExplanation(question.getExplanation());
        nextQuestionVo.setIsNewRule(question.getIsNewRule());
        nextQuestionVo.setIsHot(question.getIsHot());
        nextQuestionVo.setStatus(question.getStatus());
        nextQuestionVo.setDifficulty(question.getDifficulty());
        nextQuestionVo.setQuestionType(question.getQuestionType());
        nextQuestionVo.setSource(question.getSource());
        // 查询题目选项
        LambdaQueryWrapper<QuestionOption> questionOptionEw = new LambdaQueryWrapper<>();
        questionOptionEw.eq(QuestionOption::getQuestionId, question.getId());
        questionOptionEw.orderByAsc(QuestionOption::getSortOrder);
        List<QuestionOption> questionOptions = questionOptionMapper.selectList(questionOptionEw);
        nextQuestionVo.setOptions(questionOptions);
        List<String> answers = questionOptions.stream()
                .filter(questionOption -> questionOption.getIsCorrect().equals(BaseConstants.YES))
                .map(QuestionOption::getOptionCode)
                .collect(Collectors.toList());
        nextQuestionVo.setAnswers(answers);
        // 查询正确率
        Double correctRate = answerRecordMapper.getCorrectRate(question.getId());
        nextQuestionVo.setCorrectRate(correctRate == null ? 0 : correctRate);
        return nextQuestionVo;
    }

    @Override
    public NextQuestionVo getNextQuestionByType(Long typeId) {
        Question question = questionMapper.getRandomQuestionByType(typeId);
        if (question == null){
            return null;
        }
        NextQuestionVo nextQuestionVo = new NextQuestionVo();

        nextQuestionVo.setId(question.getId());
        nextQuestionVo.setContent(question.getContent());
        nextQuestionVo.setContentImage(question.getContentImage());
        nextQuestionVo.setKeyPoint(question.getKeyPoint());
        nextQuestionVo.setExplanation(question.getExplanation());
        nextQuestionVo.setIsNewRule(question.getIsNewRule());
        nextQuestionVo.setIsHot(question.getIsHot());
        nextQuestionVo.setStatus(question.getStatus());
        nextQuestionVo.setDifficulty(question.getDifficulty());
        nextQuestionVo.setQuestionType(question.getQuestionType());
        nextQuestionVo.setSource(question.getSource());
        // 查询题目选项
        LambdaQueryWrapper<QuestionOption> questionOptionEw = new LambdaQueryWrapper<>();
        questionOptionEw.eq(QuestionOption::getQuestionId, question.getId());
        questionOptionEw.orderByAsc(QuestionOption::getSortOrder);
        List<QuestionOption> questionOptions = questionOptionMapper.selectList(questionOptionEw);
        nextQuestionVo.setOptions(questionOptions);
        List<String> answers = questionOptions.stream()
                .filter(questionOption -> questionOption.getIsCorrect().equals(BaseConstants.YES))
                .map(QuestionOption::getOptionCode)
                .collect(Collectors.toList());
        nextQuestionVo.setAnswers(answers);
        // 查询正确率
        Double correctRate = answerRecordMapper.getCorrectRate(question.getId());
        nextQuestionVo.setCorrectRate(correctRate == null ? 0 : correctRate);
        return nextQuestionVo;
    }


}
